package com.shao;

import com.shao.annotation.discovery.SrpcApi;
import com.shao.channelHandler.handler.MethodCallHandler;
import com.shao.channelHandler.handler.SrpcRequestDecoder;
import com.shao.channelHandler.handler.SrpcResponseEncoder;
import com.shao.discovery.RegistryConfig;
import com.shao.heartbeatDetector.HeartbeatDetection;
import com.shao.loadBalance.LoadBalancer;
import com.shao.transport.message.SrpcRequest;
import com.shao.utils.PackageUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author PaoFu
 * @version 1.0
 * @data 2025/4/3 15:14
 */
@Slf4j
@Getter
public class SrpcBootstrap {

    private static final SrpcBootstrap srpcBootstrap = new SrpcBootstrap();

    private final Configuration configuration;

    public static ThreadLocal<SrpcRequest> REQUEST_THREAD_LOCAL = new ThreadLocal<>();

    // 可用的服务列表
    public static final Map<String, ServiceConfig> SERVICE_LIST = new ConcurrentHashMap<>(16);
    // 全局的 Channel 管道
    public static final Map<InetSocketAddress, Channel> SOCKET_CHANNEL = new ConcurrentHashMap<>(16);
    public static final TreeMap<Long, Channel> SHORTEST_RESPONSE_TIME_CHANNEL = new TreeMap<>();
    // 全局的挂起的请求
    public static final Map<Long, CompletableFuture<Object>> PENDING_REQUEST = new ConcurrentHashMap<>(128);

    private SrpcBootstrap() {
        configuration = new Configuration();
    }

    /**
     * 获取单例
     * @return this当前实例
     */
    public static SrpcBootstrap getInstance() {
        if (srpcBootstrap == null) {
            throw new IllegalArgumentException("SrpcBootstrap 未正确初始化，请检查日志中的异常信息");
        }
        return srpcBootstrap;
    }

    /**
     * 定义当前应用的名字
     * @param appName 当前应用名
     * @return this当前实例
     */
    public SrpcBootstrap application(String appName) {
        configuration.setAppName(appName);
        if (log.isDebugEnabled()) {
            log.debug("当前应用名 - {}", appName);
        }
        return this;
    }

    /*
      --------------------------------服务提供方的相关API------------------------------------
     */
    /**
     * 配置注册中心
     * @return this当前实例
     */
    public SrpcBootstrap registry() {
        RegistryConfig registryConfig = new RegistryConfig(configuration.getRegistryUrl());
        configuration.setRegistryConfig(registryConfig);
        if (log.isDebugEnabled()) {
            log.debug("当前配置的注册中心 - {}", registryConfig);
        }
        return this;
    }
    public SrpcBootstrap registry(RegistryConfig registryConfig) {
        configuration.setRegistryConfig(registryConfig);
        if (log.isDebugEnabled()) {
            log.debug("当前配置的注册中心 - {}", registryConfig);
        }
        return this;
    }

    /**
     * 配置负载均衡
     * @return this当前实例
     */
    public SrpcBootstrap loadBalance(LoadBalancer loadBalancer) {
        configuration.setLoadBalancer(loadBalancer);
        if (log.isDebugEnabled()) {
            log.debug("当前配置的负载均衡策略 - {}", loadBalancer);
        }
        return this;
    }

    /**
     * 配置当前暴露的服务使用的协议
     * @param protocolConfig 协议的封装
     * @return this当前实例
     */
    public SrpcBootstrap protocol(ProtocolConfig protocolConfig) {
        configuration.setProtocolConfig(protocolConfig);
        if (log.isDebugEnabled()) {
            log.debug("当前服务使用的协议 - {}", protocolConfig);
        }
        return this;
    }

    /**
     * 发布服务
     * @param service 封装需要发布的服务
     * @return this当前实例
     */
    public SrpcBootstrap publish(ServiceConfig service) {
        configuration.getRegistryConfig().getRegistry().registry(service);
        if (log.isDebugEnabled()) {
            log.debug("服务【{}】已经被发布", service);
        }
        SERVICE_LIST.put(service.getInterface().getName(), service);
        return this;
    }

    /**
     * 批量发布服务
     * @param services 封装需要发布的服务列表
     * @return this当前实例
     */
    @SuppressWarnings("all")
    public SrpcBootstrap publish(List<ServiceConfig> services) {
        AtomicReference<SrpcBootstrap> srpcBootstrap = new AtomicReference<>(this);
        services.forEach(service -> {
            srpcBootstrap.set(publish(service));
        });
        return srpcBootstrap.get();
    }

    /**
     * 启动Netty服务
     */
    public void start() {
        NioEventLoopGroup boss = new NioEventLoopGroup(2);
        NioEventLoopGroup worker = new NioEventLoopGroup(10);
        try {
            ServerBootstrap sbs = new ServerBootstrap();
            ChannelFuture channelFuture = sbs.group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel sc) {
                        sc.pipeline()
                                .addLast(new LoggingHandler(LogLevel.DEBUG))
                                .addLast(new SrpcRequestDecoder())
                                .addLast(new SrpcResponseEncoder())
                                .addLast(new MethodCallHandler());
                    }
                }).bind(configuration.getPort()).sync();
            log.info("在{}地址上监听", channelFuture.channel().localAddress());
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                boss.shutdownGracefully().sync();
                worker.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                log.error("Netty优雅关机发生异常", e);
            }
        }
    }


     /*
      --------------------------------服务调用方的相关API------------------------------------
     */

    @SuppressWarnings("all")
    public SrpcBootstrap reference(ReferenceConfig<?> reference) {
        // 开启心跳检测
        HeartbeatDetection.heartbeatDetection(reference.getInterface().getName());
        // 把相关的配置项配置到注册中心
        reference.setRegistry(configuration.getRegistryConfig().getRegistry());
        return this;
    }

    public SrpcBootstrap serialize(String serializeType) {
        configuration.setSerializeType(serializeType);
        return this;
    }

    /**
     * 扫包
     * @param packageName 包名
     * @return SrpcBootstrap
     */
    public SrpcBootstrap scan(String packageName) {
        try {
            // 扫包
            List<Class<?>> classes = PackageUtils.scanAnnotatedClasses(packageName, SrpcApi.class).stream().toList();
            if (!classes.isEmpty()) {
                // 根据反射构建实现
                List<ServiceConfig> serviceConfigs = new LinkedList<>();
                for (Class<?> clazz : classes) {
                    Class<?>[] interfaces = clazz.getInterfaces();
                    try {
                        Object ref = clazz.getConstructor().newInstance();
                        Arrays.stream(interfaces).toList()
                                .forEach(anInterface -> serviceConfigs.add(
                                        new ServiceConfig().setInterface(anInterface).setRef(ref))
                                );
                    } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                             NoSuchMethodException e) {
                        log.error("扫包根据反射构建实现【{}】时发生异常", clazz.getName(), e);
                    }
                }
                // 发布
                publish(serviceConfigs);
            }
            return this;
        } catch (IOException e) {
            log.error("服务启动时扫包发生异常", e);
            throw new RuntimeException();
        }
    }
}
